package com.itheima.reggie.web;

import com.alibaba.fastjson.JSON;
import com.itheima.reggie.common.BaseContext;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.Employee;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 *   @WebFilter  web阶段的注解
 *      作用  web项目启动的时候 会发现这个注解
 *            就会 创建Filter对象.
 *     现在 对象交给spring搞了
 *        spring是不是得能发现  web里面规定的注解
 *        spring容器默认的扫描能扫描到它吗? 不能
 *     需要在 springboot引导类中
 *       开启 对 web里面规定的组件  注解进行扫描
 */
@WebFilter(filterName = "LoginCheckFilter")
@Slf4j
public class LoginCheckFilter implements Filter {
    /**
     * 1:默认写的过滤器 会拦截所有的请求
     *     /backend/page/login/login.html  html页面
     *     /backend/styles/common.css    css资源
     *     /employee/login     登录请求
     *     /employee/page      分页查询请求
     *  2:都哪些资源 直接被放行  不需要做权限校验
     *    剩下的就是需要做权限校验的了
     *    什么资源要放行呢?
     *       静态资源 放行
     *              /backend/**
     *              /front/**
     *      动态资源 --真实的数据
     *          /employee/login
     *          /employee/logout
     */
    // 把 需要放行的(认证过的) 路径 放到一个数组中 进行统一管理
    private String[] authURL=new String[]{
            "/backend/**",
            "/front/**",
            "/employee/login",
            "/employee/logout",
            "/common/**",  //对公共操作的  上传和下载进行放行
              //放行前台用户的 登录请求 和获取验证码请求
            "/user/sendMsg",
            "/user/login",
            "/doc.html",
            "/webjars/**",
            "/swagger-resources",
            "/v2/api-docs"
    };
    /**
     *   获取拦截请求路径 去匹配 上面认证过得路径数组
     *    如果匹配成功 返回true
     *    如果匹配失败 返回false
     * @param requestURI  拦截的请求路径 假设 /backend/page/login/login.html
     * @return
     */
    private boolean isCheckUrl(String requestURI) {
        //隆重介绍一个类  spring框架 好人 提供一个可以判断规则和路径 匹配的对象
        //   pathMatcher.match(url,requestURI) 前面写规则 后面写路径
        //                  判断路径符不符合规则
        // spring路径匹配器
        AntPathMatcher pathMatcher = new AntPathMatcher();
        //遍历数组
        for (String url : authURL) {
            //怎么完成 url 和  requestURI 的匹配
            // 先判断是以什么开头的 再进行截取 再判断....
            // 百度 问  有没有这样的对象 实现了 匹配规则和路径的匹配判断
           if(pathMatcher.match(url,requestURI)){
               return true;
           }
        }
        return false;
    }
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
         //父怎么变成子?  向下转型
        //向下转型
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)resp;
        // 1:获取本次请求的URI
        String requestURI = request.getRequestURI();

        log.info(requestURI+"[被过滤器 拦截住了.....]");
       // 2:拿到 请求路径 是不是 要跟 认证的路径 进行比对!!
        boolean isCheck = isCheckUrl(requestURI);
        // 3:如果比对成功就放行
        if(isCheck){
            //比对成功 认证的哪些路径 是不需要 进行登录判断的
            // 所以放行
            chain.doFilter(request, response);
            return;//不用继续了
        }
        // 不成功说明没有 return 就拦截 检查用户是否登录
         //  4: 判断用户登录状态.. session中有个 employee 有登录 没有就是没登录
        Object empID = request.getSession().getAttribute("employee");

        if(empID!=null){//登录着呢  放行
           log.info("[登录检查,后台用户已登录,可以放行]:"+empID);
           //查看当前线程id
            long id = Thread.currentThread().getId();
            log.info("过滤器的线程id:"+id);

            // 在过滤器这里把empId,存储到ThreadLocal对象中
            BaseContext.setCurrentId((Long)empID);
            chain.doFilter(request, response);
            return;//不用继续了
        }
        // 将来这块还得判断 前台用户是否登陆成功 ...
        Object userID = request.getSession().getAttribute("user");

        if(userID!=null){//登录着呢  放行
            log.info("[登录检查,前台用户已登录,可以放行]:"+userID);
            //查看当前线程id
            long id = Thread.currentThread().getId();
            log.info("过滤器的线程id:"+id);

            // 在过滤器这里把userId,存储到ThreadLocal对象中
            BaseContext.setCurrentId((Long)userID);
            chain.doFilter(request, response);
            return;//不用继续了
        }

        //如果代码到这里 说明路径不在 放行范围内 也没登录
        log.info("[因为没登录,所以没有权限,请登录]");
       // 应该重定向到登录页面  谁重定向 是前端还是后端
        // 需要我们想要 一个json格式的结果对象   里面包含  code 0 msg = "NOTLOGIN"
        R r = R.error("NOTLOGIN");
        // 在不是处理器代码上  怎么把数据变成json格式  响应给前端
        String s = JSON.toJSONString(r);//s就json格式对象
        //怎么响应给前端
        response.getWriter().write(s);
    }



    public void destroy() {
    }



    public void init(FilterConfig config) throws ServletException {

    }

}
